package game.engine.base

import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.RectF
import java.lang.RuntimeException
import java.lang.StringBuilder
import kotlin.collections.ArrayList

// 暂时不考虑优化
// Node 可以想象成一个点
open class Node @JvmOverloads constructor(
        var x: Float = 0f,
        var y: Float = 0f,
        var degress: Float = 0f,
        ax: Float = 0.5f,
        ay: Float = 0.5f,
        var sx: Float = 1.0f,
        var sy: Float = 1.0f,
        var zorder: Int = 0,
) : Comparable<Node> {

    companion object {

        var nodeGlobalId = 0
        fun genNodeId(): Int = ++nodeGlobalId

        /**
         * 将 worldPos 坐标,转换成 parentNode下的坐标
         *
         *  localPos -> worldPos :
         *    WorldMatrix * localPos = worldPos
         *    localPos = Inv(WorldMatrix) * worldPos
         */
        fun transformWorldParentToLocalPos(parentNode:Node,worldPos: Vec2):Vec2{
            parentNode.updateWorldMatrix()
            val invMat = Matrix()
            parentNode.worldMatrix.invert(invMat)
            val floatArr = floatArrayOf(worldPos.x,worldPos.y)
            invMat.mapPoints(floatArr)
            return Vec2(floatArr[0],floatArr[1])
        }

        /**
         * 将 parentNode 下的 rect 转换成 世界坐标系下的  rect
         */
        fun transformLocalRectToWorldRect(parentNode: Node,localRect:RectF):RectF{
            parentNode.updateWorldMatrix()
            val dstRect = RectF()
            parentNode.worldMatrix.mapRect(dstRect,localRect)
            return  dstRect
        }
    }

    var verticeDirty = false
    var ax = ax
        set(value) {
            field = value
            verticeDirty = true
        }
    var ay = ay
        set(value) {
            field = value
            verticeDirty = true
        }


    var tag: Int = -1
    val nodeId = genNodeId()
    var willDestroy = false

    var parent: Node? = null
    open var children: ArrayList<Node>? = null

    val finalMatrix = Matrix()
    val worldMatrix = Matrix()

    var visible = true

    //------------------------------------------
    // 场景树管理
    fun addChild(child: Node) {
        if (CoreDebug.NodeDebug) {
            if (child.parent != null) throw RuntimeException("child already in scene graph")
        }
        child.parent = this
        if (children == null) {
            children = ArrayList()
        }
        children!!.add(child)

        if (CoreDebug.NodeDebug) {
            CoreDebug.info("child:${child.nodeId} add to scene graph!")
        }
    }

    // 只是做一个标记
    // 实际删除是在  一帧中 渲染之前进行删除
    fun removeChild(child: Node) {
        child.willDestroy = true
        child.children?.forEach { it ->
            it.removeFromParent()
        }
    }

    fun removeFromParent() {
        willDestroy = true
        children?.forEach { it -> it.removeFromParent() }
    }

    fun getChildByTag(pTag: Int): Node? {
        if (CoreDebug.NodeDebug) {
            if (pTag < 0) {
                CoreDebug.warn("pTag:${pTag} < 0. pTag 应该 >= 0")
            }
        }
        return children?.find { it.tag == pTag }
    }

    //------------------------------
    // 真正的从场景树中剔除
    // 并且释放资源
    fun removeDiedChildren() {
        if (children != null) {
            val iter = children!!.iterator()
            while (iter.hasNext()) {
                val child = iter.next()
                if (child.willDestroy) {
                    // 直接从场景树中剔除
                    child.realRemove()
                    iter.remove()
                } else {
                    child.removeDiedChildren()
                }
            }
        }
    }

    private fun realRemove() {

        // 清除子节点
        children?.forEach {
            it.realRemove()
        }
        // 自己 release
        onRelease()
    }

    fun updateWorldMatrix() {
        if (parent == null){
            if (CoreDebug.NodeDebug){
                if (!(this is Scene)){
                    CoreDebug.warn("node:$nodeId 还没加入场景树!")
                }
            }
        }else{
            var p = parent!!
            p.updateWorldMatrix()
            var worldMat = p.worldMatrix
            worldMatrix.set(worldMat)
            worldMatrix.preTranslate(x,y)
            worldMatrix.preRotate(degress)
            worldMatrix.preScale(sx, sy)
        }
    }

    fun getWorldPos(): Vec2 {
        updateWorldMatrix()
        worldMatrix.getValues(CoreUtil.tmpMatrixArray)
        return Vec2(CoreUtil.tmpMatrixArray[2],CoreUtil.tmpMatrixArray[5])
    }

    //-------------------------------------
    // 子类需要重写的方法
    open fun onRelease() {}
    open fun onDraw(canvas: Canvas) {}

    open fun updateFinalMatrixInRender(parentMatrix: Matrix) {
        finalMatrix.set(parentMatrix)
        finalMatrix.preTranslate(x, y)
        finalMatrix.preRotate(degress)
        finalMatrix.preScale(sx, sy)
    }

    fun draw(canvas: Canvas, parentMatrix: Matrix) {

        if (visible) {

            // 处于visible状态,才会更新worldMatrix
            // updateWorldMatrixForRender()
            updateFinalMatrixInRender(parentMatrix)

            // 先绘制自己,再绘子节点
            onDraw(canvas)

            children?.sort()
            children?.forEach { child -> child.draw(canvas, finalMatrix) }
        }
    }

    // z越小 越先绘制
    override fun compareTo(other: Node): Int {
        return this.zorder - other.zorder
    }
}


fun Node.show_scene_graph(depth: Int = 0): String {
    val sb = StringBuilder()
    for (i in 0 until depth) {
        sb.append("--")
    }
    sb.append("nodeId:$nodeId,z:${zorder}\n")
    children?.forEach {
        sb.append(it.show_scene_graph(depth + 1))
    }
    return sb.toString()
}


